package main

import (
	"crypto/md5"
	"fmt"
	"io"
	"math/rand"
	"net/http"
	"net/http/cookiejar"
	"os"
	"regexp"
	"strings"
	"time"
)

type Auth struct {
	Force_Auth string
	Force_Code string
	Force_Pwd  string
}

var sid_reg = regexp.MustCompile("http://static.kaoshidian.com/doc/play/2.0/XAPlayer.swf[?]sid=(.*)&replay=0&baseUrl=http://www.kaoshidian.com&t=")
var movie_reg = regexp.MustCompile("<param name=\"movie\" value=\"(.*)\">")
var illegal_char_1 = regexp.MustCompile("[/\\\\:*?|]")
var illegal_char_2 = regexp.MustCompile("[\"<>]")
var vodUrlsReg = regexp.MustCompile("\"vodUrls\":\"(.*)\"")
var chapterNameReg = regexp.MustCompile("\"chapterName\":\"(.*)\",\"defaultHigh\"")

type Downloader struct {
	io.Reader
	Total   int64
	Current int64
}

func (d *Downloader) Read(p []byte) (n int, err error) {
	n, err = d.Reader.Read(p)
	d.Current += int64(n)
	fmt.Printf("\r正在下载，下载进度：%.2f%%", float64(d.Current*10000/d.Total)/100)
	if d.Current == d.Total {
		fmt.Printf("\r下载完成，下载进度：%.2f%%", float64(d.Current*10000/d.Total)/100)
	}
	return
}

func downloadVideo(_url string, force_auth string, filename string) {
	//先创建一个 Auth 对象
	auth := Auth{}
	//Force_Auth就是当前秒数
	auth.Force_Auth = force_auth
	//Force_Code就是当前秒数的md5
	auth.Force_Code = fmt.Sprintf("%x", md5.Sum([]byte(auth.Force_Auth)))
	//Force_Pwd就是 （当前秒数md5+"27616152020030210"+Force_Auth） 的md5
	auth.Force_Pwd = fmt.Sprintf("%x", md5.Sum([]byte(auth.Force_Code+"27616152020030210"+auth.Force_Auth)))
	fmt.Println("密钥信息：", auth)
	client := http.DefaultClient
	request, _ := http.NewRequest("POST", _url, strings.NewReader("SDF=SDF"))
	request.Header.Set("Accept", "*/*")
	request.Header.Set("Accept-Encoding", "gzip, deflate")
	request.Header.Set("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8")
	request.Header.Set("Connection", "keep-alive")
	request.Header.Set("Content-Length", "7")
	request.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	request.Header.Set("Force_Auth", auth.Force_Auth)
	request.Header.Set("Force_Code", auth.Force_Code)
	request.Header.Set("Force_Pwd", auth.Force_Pwd)
	request.Header.Set("Host", "vod2.21xuexi.net")
	request.Header.Set("Origin", "http://static.kaoshidian.com")
	request.Header.Set("Referer", "http://static.kaoshidian.com/doc/play/2.0/XAPlayer.swf?sid=4226ab4e1bcf47f7&replay=0&baseUrl=http://www.kaoshidian.com&t=")
	request.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.112 Safari/537.36")
	request.Header.Set("X-Requested-With", "ShockwaveFlash/29.0.0.171")

	response, _ := client.Do(request)

	if len(filename) == 0 {
		filename = "download_" + auth.Force_Auth + ".flv"
	} else if !strings.Contains(filename, ".flv") {
		filename += ".flv"
	}
	filename = illegal_char_1.ReplaceAllString(filename, "_")
	filename = illegal_char_2.ReplaceAllString(filename, "")

	file, _ := os.OpenFile(filename, os.O_RDWR|os.O_CREATE, 0755)

	fmt.Printf("文件大小 %d 字节，命名为：%s\n", response.ContentLength, filename)
	downloader := &Downloader{
		Reader: response.Body,
		Total:  response.ContentLength,
	}
	io.Copy(file, downloader)
	file.Close()

}

func getServerTS(_url string) string {
	response, _ := http.Get(_url)
	all, _ := io.ReadAll(response.Body)
	return string(all)
}

func getPlayerSid(_url string) (string, string) {
	response, _ := http.Get(_url)
	all, _ := io.ReadAll(response.Body)
	sall := string(all)
	movie_submatch := movie_reg.FindAllStringSubmatch(sall, 1)
	sid_submatch := sid_reg.FindAllStringSubmatch(movie_submatch[0][1], 1)
	return movie_submatch[0][1], sid_submatch[0][1]
}

func getPlayList(movie string, sid string) (string, string) {
	//version := rand.Float64() * float64(time.Now().Unix())
	version := fmt.Sprintf("%f", rand.Float64()*float64(time.Now().Unix()))
	fmt.Println(version)
	playCode := sid
	request, _ := http.NewRequest("POST", "http://www.kaoshidian.com/player/toplay?v="+version, strings.NewReader(
		"playCode="+playCode+"&version="+strings.Replace(version, ".", "%2E", 1)))
	request.Header.Set("Accept", "*/*")
	request.Header.Set("Accept-Encoding", "gzip, deflate")
	request.Header.Set("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8")
	request.Header.Set("Connection", "keep-alive")
	request.Header.Set("Content-Length", "53")
	request.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	request.Header.Set("Host", "www.kaoshidian.com")
	request.Header.Set("Origin", "http://static.kaoshidian.com")
	request.Header.Set("Referer", movie)
	request.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.112 Safari/537.36")
	request.Header.Set("X-Requested-With", "ShockwaveFlash/29.0.0.171")
	client := http.DefaultClient
	response, _ := client.Do(request)
	all, _ := io.ReadAll(response.Body)

	sall := string(all)
	chapterName_submatch := chapterNameReg.FindAllStringSubmatch(sall, 1)
	vod_submatch := vodUrlsReg.FindAllStringSubmatch(sall, 1)
	split1 := strings.Split(vod_submatch[0][1], "&")
	if len(split1) > 1 && strings.Contains(split1[0], "HIGH=") {
		split2 := strings.Split(split1[0], "=")
		return chapterName_submatch[0][1], split2[1]
	} else {
		split2 := strings.Split(split1[1], "=")
		return chapterName_submatch[0][1], split2[1]
	}
}

func main() {
	args := os.Args
	client := http.DefaultClient
	client.Jar, _ = cookiejar.New(nil)
	for _, item := range args {
		if strings.Contains(item, "http") {
			movie, sid := getPlayerSid(item)
			chapterName, videoUrl := getPlayList(movie, sid)
			downloadVideo(videoUrl, getServerTS(videoUrl), chapterName)
		}
	}
}
